#include	"StateMachine.h"
#include	"IState.h"
#include	<Configuration/Config.h>
#include	<Window/Window.h>
#include	<Sound/SoundSystem.h>
#include	<Font/Font.h>
#include	<GUI/Mouse.h>
#include	<assert.h>

StateMachine::StateMachine(Config * config, Window * window, Mouse * mouse, SoundSystem * soundSystem, Font * font)
	:	m_state()
	,	m_active()
	,	m_config(config)
	,	m_window(window)
	,	m_mouse(mouse)
	,	m_soundSystem(soundSystem)
	,	m_font(font)
	,	m_timeInState(1.0)
{
	assert(m_config != 0);
	assert(m_window != 0);
	assert(m_mouse != 0);
	assert(m_soundSystem != 0);
	assert(m_font != 0);
}

StateMachine::~StateMachine()
{
	m_active.clear();
	m_state.clear();
}

void StateMachine::update(double delay)
{
	m_timeInState += delay;
	if(m_active.size() != 0)
	{
		std::vector< IState * >::size_type index = m_active.back();
		assert(index < m_state.size());
		m_state[index]->update(delay);
	}
}

void StateMachine::render() const
{
	if(m_active.size() != 0)
	{
		std::vector< IState * >::size_type index = m_active.back();
		assert(index < m_state.size());
		m_state[index]->render();
	}
}

void StateMachine::push(unsigned int id, double requireTime)
{
	if((requireTime <= m_timeInState) || (m_active.size() == 0))
	{
		if(m_active.size() != 0)
		{
			std::vector< IState * >::size_type index = m_active.back();
			assert(index < m_state.size());
			m_state[index]->changingState(false);
		}
		std::vector< IState * >::size_type index = findIndex(id);
		if(index != std::vector< IState * >::size_type(-1))
		{
			m_active.push_back(index);
		}
		m_state[index]->changingState(true);
		m_timeInState = 0.0;
	}
}

void StateMachine::pop(double requireTime)
{
	if(requireTime < m_timeInState)
	{
		std::vector< IState * >::size_type index = m_active.back();
		m_state[index]->changingState(false);
		m_active.pop_back();
		if(m_active.size() != 0)
		{
			std::vector< IState * >::size_type index = m_active.back();
			assert(index < m_state.size());
			m_state[index]->changingState(true);
		}
		else
		{
			m_window->TimeToQuit();
		}
		m_timeInState = 0.0;
	}
}

void StateMachine::addStatePointer(IState * state)
{
	m_state.push_back(state);
}

Config * StateMachine::getConfig()
{
	return m_config;
}

Window * StateMachine::getWindow()
{
	return m_window;
}

Mouse * StateMachine::getMouse()
{
	return m_mouse;
}

SoundSystem * StateMachine::getSoundSystem()
{
	return m_soundSystem;
}

Font * StateMachine::getFont()
{
	return m_font;
}

std::vector< IState * >::size_type StateMachine::findIndex(unsigned int id)
{
	std::vector< IState * >::size_type index = 0;
	for(std::vector< IState * >::const_iterator it = m_state.begin();
		it != m_state.end(); ++it, ++index)
	{
		if((*it)->Id() == id)
		{
			return index;
		}
	}
	return std::vector< IState * >::size_type(-1);
}

double StateMachine::getTimeInState() const
{
	return m_timeInState;
}

